//
//	readMarix
//	11th attestation
//
//	author: Tobias Stein
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//definitions
#define MAX 15
#define ARGUMENT_IMPORT_FAILURE  -1
#define MATRIX_IMPORT_FAILURE    -2

/**
 *	readMatrix
 *
 *	Reading matrix out of file, writing it in array.
 *	@parameter	argv	Array.
 *	@parameter	n		Matrix width.
 *	@parameter	m		Matrix height.
 *	@return				Array with matrix.
 */
float* readMatrix(char* filename,int n, int m)
{
	float* matrix=NULL;
	char* buffer=(char*)malloc(MAX*sizeof(char));
	FILE* file=NULL;
	file=fopen(filename,"r");
	if(file==NULL)
	{
		printf("\nCOULD NOT OPEN \"%s\"!\n",filename);
		return NULL;
	}
	matrix=(float *)malloc(n*m*sizeof(float));
	if(matrix==NULL)
	{
		printf("\nALLOCATION FAILURE!\n");
		return NULL;
	}
	for(int i=1;i<=3;i++)
	{
		fgets(buffer,MAX,file);
	}
	for(int i=0;i<n*m;i++)
	{
			fscanf(file,"%f",matrix+i);
	}
	return matrix;
}

/**
 *	readSymmetricMatrix
 *
 *	Reading symmetric matrix out of file, writing it in array.
 *	@parameter	filename	Array.
 *	@parameter	n			Matrix width/height.
 *	@return					Array with matrix.
 */
float* readSymmetricMatrix(char* filename, int n)
{
	float* matrix=NULL;
	char* buffer=(char*)malloc(MAX*sizeof(char));
	FILE* file=NULL;
	file=fopen(filename,"r");
	if(file==NULL)
	{
		printf("\nCOULD NOT OPEN \"%s\"!\n",filename);
		return NULL;
	}
	matrix=(float*)malloc(n*(n+1)/2*sizeof(float));
	if(matrix==NULL)
	{
		printf("\nALLOCATION FAILURE!\n");
		return NULL;
	}
	for(int i=1;i<=3;i++)
	{
		fgets(buffer,MAX,file);
	}
	for(int i=0;i<n*(n+1)/2;i++)
	{
		fscanf(file,"%f",matrix+i);
	}
	return matrix;
}

/**
 *	readToeplitzMatrix
 *
 *	Reading Toeplitz-matrix out of file, writing it in array.
 *	@parameter	filename	Array.
 *	@parameter	n			Matrix width.
 *	@parameter	m			Matrix height.
 *	@return					Array with matrix.
 */
float* readToeplitzMatrix(char* filename,int n, int m)
{
	float* matrix=NULL;
	char* buffer=(char*)malloc(MAX*sizeof(char));
	FILE* file=NULL;
	file=fopen(filename,"r");
	if(file==NULL)
	{
		printf("\nCOULD NOT OPEN \"%s\"!\n",filename);
		return NULL;
	}
	matrix=(float*)malloc(n*m*sizeof(float));
	if(matrix==NULL)
	{
		printf("\nALLOCATION FAILURE!\n");
		return NULL;
	}
	for(int i=1;i<=3;i++)
	{
		fgets(buffer,MAX,file);
	}
	for(int i=0;i<n*m;i++)
	{
		fscanf(file,"%f",matrix+i);
	}
	return matrix;
}

/**
 *	readSymmetricToeplitzMatrix
 *
 *	Reading symmetric Toeplitz-matrix out of file, writing it in array.
 *	@parameter	filename	Array.
 *	@parameter	n			Matrix width/height.
 *	@return					Array with matrix.
 */
float* readSymmetricToeplitzMatrix(char* filename,int n)
{
	float* matrix=NULL;
	char* buffer=(char*)malloc(MAX*sizeof(char));
	FILE* file=NULL;
	file=fopen(filename,"r");
	if(file==NULL)
	{
		printf("\nCOULD NOT OPEN \"%s\"!\n",filename);
		return NULL;
	}
	matrix=(float*)malloc(n*sizeof(float));
	if(matrix==NULL)
	{
		printf("\nALLOCATION FAILURE!\n");
		return NULL;
	}
	for(int i=1;i<=3;i++)
	{
		fgets(buffer,MAX,file);
	}
	for(int i=0;i<n;i++)
	{
		fscanf(file,"%f",matrix+i);
	}
	return matrix;
}
/**
 *	getMatrixType
 *
 *	Getting type and dimensions of matrix out of the inserted file.
 *
 *	@parameter	filename	Name of matrixfile.
 *	@parameter	n			Number of Cols.
 *	@parameter	m			Number of Rows.
 *	@return					Integer of type of matrix.
 */
int getMatrixType(char* filename, int* n, int* m)
{
	char* type=(char*)malloc(MAX*sizeof(char));
	char* buffer=(char*)malloc(MAX*sizeof(char));
	FILE* file=NULL;
	file=fopen(filename,"r");
	if(file==NULL)
	{
		printf("\nCOULD NOT OPEN \"%s\"!\n",filename);
		return -2;
	}
	fgets(buffer,MAX,file);
	*n=atoi(&buffer[(strlen(buffer))-2]);
	fgets(buffer,MAX,file);
	*m=atoi(&buffer[(strlen(buffer))-2]);
	fgets(buffer,MAX,file);
	for(unsigned int counter=5;buffer[counter]!='\n'&&buffer[counter]!='\0';counter++)
	{
		type[counter-5]=buffer[counter];
	}
	if(strcmp(type,"matrix")==0)
	{
		return 1;
	}
	else if (strcmp(type,"sym_low")==0)
	{
		return 2;
	}
	else if (strcmp(type,"toep")==0)
	{
		if(*n>10||*m>10)
		{
			return 0;
		}
		return 3;
	}
	else if (strcmp(type,"sym_toep")==0)
	{
		if(*n>10||*m>10)
		{
			return 0;
		}
		return 4;
	}
	else
	{
		return 0;
	}
}

/**
 *	printMatrix
 *
 *	Printing Matrix.
 *	@parameter	filename	Filename of matrixfile.
 *	@parameter	n			Height of matrix.
 *	@parameter	m			Width of matrix.
 *	@parameter	t			Type of matrix.
 *	@return					Integer for successful exit or failure flag.
 */
int printMatrix(char* filename, int n, int m, int t)
{
	float* A=NULL;
	switch(t)
	{
		case 1:	if((A=readMatrix(filename,n,m))==NULL)
				{
					return -2;
				}
				printf("\n%dx%d-matrix:\n",n,m);
				for(int i=0;i<m;i++)
				{
					for(int j=0;j<n;j++)
					{
					printf("%8.3f",A[i*n+j]);
					}
					putchar('\n');
				}
				return 0;
		case 2:	if((A=readSymmetricMatrix(filename,n))==NULL)
				{
					return -2;
				}
				printf("\nSymmetric matrix:\n");
				for(int i=1;i<=n;i++)
				{
					for(int j=1;j<=i;j++)
					{
						printf("%8.3f",A[((i)*((i)-1)/2+(j)-1)]);
					}
					putchar('\n');
				}
				return 0;
		case 3:	if((A=readToeplitzMatrix(filename,n,m))==NULL)
				{
					return -2;
				}
				printf("\nToeplitz-matrix:\n");
				for(int i=1;i<=m;i++)
				{
					for(int j=1;j<=n;j++)
					{
						switch(i-j)
						{	
							case -9:printf("%8.3f",A[9]);
									break;
							case -8:printf("%8.3f",A[8]);
									break;
							case -7:printf("%8.3f",A[7]);
									break;
							case -6:printf("%8.3f",A[6]);
									break;
							case -5:printf("%8.3f",A[5]);
									break;
							case -4:printf("%8.3f",A[4]);
									break;
							case -3:printf("%8.3f",A[3]);
									break;
							case -2:printf("%8.3f",A[2]);
									break;
							case -1:printf("%8.3f",A[1]);
									break;
							case 0:	printf("%8.3f",A[0]);
									break;
							case 1:	printf("%8.3f",A[n]);
									break;
							case 2:	printf("%8.3f",A[n+1]);
									break;
							case 3:	printf("%8.3f",A[n+2]);
									break;
							case 4:	printf("%8.3f",A[n+3]);
									break;
							case 5:	printf("%8.3f",A[n+4]);
									break;
							case 6:	printf("%8.3f",A[n+5]);
									break;
							case 7:	printf("%8.3f",A[n+6]);
									break;
							case 8:	printf("%8.3f",A[n+7]);
									break;
							case 9:	printf("%8.3f",A[n+8]);
									break;
							default:printf("XXX");
									break;
						}
					}
					putchar('\n');
				}
				return 0;
		case 4:	if((A=readSymmetricToeplitzMatrix(filename,n))==NULL)
				{
					return -2;
				}
				printf("\nSymmetric toeplitz-matrix:\n");
				for(int i=1;i<=m;i++)
				{
					for(int j=1;j<=n;j++)
					{
						switch(i-j)
						{	
							case 0:	printf("%8.3f",A[0]);
									break;
							case -1:
							case 1:	printf("%8.3f",A[1]);
									break;
							case -2:
							case 2:	printf("%8.3f",A[2]);
									break;
							case -3:
							case 3:	printf("%8.3f",A[3]);
									break;
							case -4:
							case 4:	printf("%8.3f",A[4]);
									break;
							case -5:
							case 5:	printf("%8.3f",A[5]);
									break;
							case -6:
							case 6:	printf("%8.3f",A[6]);
									break;
							case -7:
							case 7:	printf("%8.3f",A[7]);
									break;
							case -8:
							case 8:	printf("%8.3f",A[8]);
									break;
							case -9:
							case 9:	printf("%8.3f",A[9]);
									break;
							default:printf("XXX");
									break;
						}
					}
					putchar('\n');
				}
				return 0;
		default:printf("\nUnknown Type! Try another file...\n");
				return -2;
	}
}

/**
 *	main
 *
 *	Main program.
 *	@parameter	arc		Counter of arguments.
 *	@parameter	argv[]	String filename.
 *	@return				Integer for exit.
 */
int main(int argc, char *argv[])
{
	int n, m, t, e;
	if(argc<2)
	{
		return -1;
	}
	t=getMatrixType(argv[1], &n, &m);
	e=printMatrix(argv[1], n, m, t);
	putchar('\n');
	return e;
}
